/**
 * 深度学习Unittest模式
 * 重点分析：
 * 1. HWTEST_F的使用模式
 * 2. Mock的使用模式（EXPECT_CALL, EXPECT_EQ等）
 * 3. SetUp/TearDown模式
 * 4. 测试用例命名规范
 * 5. BUILD.gn完整配置
 * 6. 高频依赖和includes
 */

const fs = require('fs');
const path = require('path');

class UnittestPatternDeepLearner {
    constructor() {
        this.patterns = {
            hwtestPatterns: [],           // HWTEST_F使用模式
            mockPatterns: [],              // Mock使用模式
            setupTeardownPatterns: [],     // SetUp/TearDown模式
            assertPatterns: [],            // 断言模式
            buildGnPatterns: [],           // BUILD.gn配置
            includePatterns: []            // 高频includes
        };
    }

    /**
     * 递归查找所有Unittest文件
     */
    findAllUnittestFiles(dir, files = []) {
        const items = fs.readdirSync(dir, { withFileTypes: true });
        
        for (const item of items) {
            const fullPath = path.join(dir, item.name);
            
            if (item.isDirectory()) {
                if (!item.name.startsWith('.') && item.name !== 'node_modules') {
                    this.findAllUnittestFiles(fullPath, files);
                }
            } else if (item.name.endsWith('_test.cpp') || item.name.endsWith('_unittest.cpp')) {
                // 检查是否在unittest目录下
                if (fullPath.includes('unittest') || fullPath.includes('test')) {
                    files.push(fullPath);
                }
            }
        }
        
        return files;
    }

    /**
     * 查找对应的BUILD.gn
     */
    findBuildGn(testFilePath) {
        const dir = path.dirname(testFilePath);
        const gnPath = path.join(dir, 'BUILD.gn');
        
        if (fs.existsSync(gnPath)) {
            return gnPath;
        }
        
        // 尝试上一级目录
        const parentDir = path.dirname(dir);
        const parentGnPath = path.join(parentDir, 'BUILD.gn');
        if (fs.existsSync(parentGnPath)) {
            return parentGnPath;
        }
        
        return null;
    }

    /**
     * 分析单个Unittest文件
     */
    analyzeUnittestFile(filePath) {
        console.log(`\n📄 分析: ${path.basename(filePath)}`);
        
        const content = fs.readFileSync(filePath, 'utf-8');
        const lines = content.split('\n');
        
        const analysis = {
            filePath,
            fileName: path.basename(filePath),
            
            // 1. HWTEST_F模式
            hwtestCases: this.extractHwtestCases(content, lines),
            
            // 2. Mock使用
            mockUsage: this.extractMockUsage(content, lines),
            
            // 3. SetUp/TearDown
            setupTeardown: this.extractSetupTeardown(content, lines),
            
            // 4. 断言模式
            assertions: this.extractAssertions(content, lines),
            
            // 5. includes
            includes: this.extractIncludes(content),
            
            // 6. 测试类
            testClasses: this.extractTestClasses(content)
        };
        
        // 分析对应的BUILD.gn
        const gnPath = this.findBuildGn(filePath);
        if (gnPath) {
            analysis.buildGn = this.analyzeBuildGn(gnPath);
        }
        
        return analysis;
    }

    /**
     * 提取HWTEST_F用例
     */
    extractHwtestCases(content, lines) {
        const cases = [];
        const pattern = /HWTEST_F\s*\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+\.\w+)\s*\)/g;
        
        let match;
        while ((match = pattern.exec(content)) !== null) {
            cases.push({
                testClass: match[1],
                testName: match[2],
                testLevel: match[3],
                fullMatch: match[0]
            });
        }
        
        return cases;
    }

    /**
     * 提取Mock使用模式
     */
    extractMockUsage(content, lines) {
        const mockPatterns = {
            expectCall: (content.match(/EXPECT_CALL/g) || []).length,
            expectEq: (content.match(/EXPECT_EQ/g) || []).length,
            expectNe: (content.match(/EXPECT_NE/g) || []).length,
            expectTrue: (content.match(/EXPECT_TRUE/g) || []).length,
            expectFalse: (content.match(/EXPECT_FALSE/g) || []).length,
            assertEq: (content.match(/ASSERT_EQ/g) || []).length,
            assertNe: (content.match(/ASSERT_NE/g) || []).length,
            assertTrue: (content.match(/ASSERT_TRUE/g) || []).length,
            assertFalse: (content.match(/ASSERT_FALSE/g) || []).length,
            mockMethod: (content.match(/MOCK_METHOD/g) || []).length
        };
        
        return mockPatterns;
    }

    /**
     * 提取SetUp/TearDown
     */
    extractSetupTeardown(content, lines) {
        return {
            hasSetUp: content.includes('void SetUp()') || content.includes('void SetUp(void)'),
            hasTearDown: content.includes('void TearDown()') || content.includes('void TearDown(void)'),
            hasSetUpTestCase: content.includes('SetUpTestCase'),
            hasTearDownTestCase: content.includes('TearDownTestCase')
        };
    }

    /**
     * 提取断言模式
     */
    extractAssertions(content, lines) {
        const assertions = [];
        
        const assertPatterns = [
            /EXPECT_EQ\s*\([^)]+\)/g,
            /EXPECT_NE\s*\([^)]+\)/g,
            /EXPECT_TRUE\s*\([^)]+\)/g,
            /EXPECT_FALSE\s*\([^)]+\)/g,
            /ASSERT_EQ\s*\([^)]+\)/g,
            /ASSERT_NE\s*\([^)]+\)/g
        ];
        
        for (const pattern of assertPatterns) {
            const matches = content.match(pattern) || [];
            assertions.push(...matches.map(m => m.trim()));
        }
        
        return assertions.slice(0, 10); // 只保留前10个示例
    }

    /**
     * 提取includes
     */
    extractIncludes(content) {
        const includes = [];
        const lines = content.split('\n');
        
        for (const line of lines) {
            const match = line.match(/#include\s+[<"]([^>"]+)[>"]/);
            if (match) {
                includes.push(match[1]);
            }
        }
        
        return includes;
    }

    /**
     * 提取测试类
     */
    extractTestClasses(content) {
        const classes = [];
        const pattern = /class\s+(\w+)\s*:\s*public\s+testing::Test/g;
        
        let match;
        while ((match = pattern.exec(content)) !== null) {
            classes.push(match[1]);
        }
        
        return classes;
    }

    /**
     * 分析BUILD.gn
     */
    analyzeBuildGn(gnPath) {
        console.log(`  📦 BUILD.gn: ${path.basename(path.dirname(gnPath))}`);
        
        const content = fs.readFileSync(gnPath, 'utf-8');
        
        return {
            filePath: gnPath,
            moduleOutPath: this.extractField(content, 'module_out_path'),
            sources: this.extractArrayField(content, 'sources'),
            includeDirs: this.extractArrayField(content, 'include_dirs'),
            deps: this.extractArrayField(content, 'deps'),
            externalDeps: this.extractArrayField(content, 'external_deps'),
            defines: this.extractArrayField(content, 'defines'),
            fullContent: content
        };
    }

    extractField(content, fieldName) {
        const match = content.match(new RegExp(`${fieldName}\\s*=\\s*"([^"]+)"`));
        return match ? match[1] : null;
    }

    extractArrayField(content, fieldName) {
        const match = content.match(new RegExp(`${fieldName}\\s*=\\s*\\[([^\\]]+)\\]`, 's'));
        if (!match) return [];
        
        const items = match[1].match(/"([^"]+)"/g) || [];
        return items.map(item => item.replace(/"/g, ''));
    }

    /**
     * 统计分析
     */
    generateStatistics(analyses) {
        console.log('\n\n' + '='.repeat(80));
        console.log('📊 Unittest模式深度分析统计报告');
        console.log('='.repeat(80));
        
        // 1. 总体统计
        console.log('\n【1️⃣  总体统计】');
        console.log(`  分析文件数: ${analyses.length}个`);
        console.log(`  有BUILD.gn: ${analyses.filter(a => a.buildGn).length}个`);
        
        // 2. HWTEST_F统计
        console.log('\n【2️⃣  HWTEST_F使用统计】');
        const totalHwtests = analyses.reduce((sum, a) => sum + a.hwtestCases.length, 0);
        console.log(`  HWTEST_F总数: ${totalHwtests}个`);
        
        // 统计测试级别分布
        const levels = {};
        analyses.forEach(a => {
            a.hwtestCases.forEach(tc => {
                levels[tc.testLevel] = (levels[tc.testLevel] || 0) + 1;
            });
        });
        
        console.log('  测试级别分布:');
        Object.entries(levels).sort((a, b) => b[1] - a[1]).forEach(([level, count]) => {
            const ratio = (count / totalHwtests * 100).toFixed(1);
            console.log(`    ✓ ${level.padEnd(20)} - ${count}个 (${ratio}%)`);
        });
        
        // 3. Mock使用统计
        console.log('\n【3️⃣  Mock/断言使用统计】');
        const mockStats = {
            EXPECT_EQ: 0,
            EXPECT_NE: 0,
            EXPECT_TRUE: 0,
            EXPECT_FALSE: 0,
            EXPECT_CALL: 0,
            ASSERT_EQ: 0,
            ASSERT_NE: 0,
            ASSERT_TRUE: 0,
            ASSERT_FALSE: 0,
            MOCK_METHOD: 0
        };
        
        analyses.forEach(a => {
            mockStats.EXPECT_EQ += a.mockUsage.expectEq;
            mockStats.EXPECT_NE += a.mockUsage.expectNe;
            mockStats.EXPECT_TRUE += a.mockUsage.expectTrue;
            mockStats.EXPECT_FALSE += a.mockUsage.expectFalse;
            mockStats.EXPECT_CALL += a.mockUsage.expectCall;
            mockStats.ASSERT_EQ += a.mockUsage.assertEq;
            mockStats.ASSERT_NE += a.mockUsage.assertNe;
            mockStats.ASSERT_TRUE += a.mockUsage.assertTrue;
            mockStats.ASSERT_FALSE += a.mockUsage.assertFalse;
            mockStats.MOCK_METHOD += a.mockUsage.mockMethod;
        });
        
        console.log('  使用频率:');
        Object.entries(mockStats).sort((a, b) => b[1] - a[1]).forEach(([type, count]) => {
            console.log(`    ✓ ${type.padEnd(20)} - ${count}次`);
        });
        
        // 4. SetUp/TearDown使用
        console.log('\n【4️⃣  SetUp/TearDown使用】');
        const setupStats = {
            hasSetUp: analyses.filter(a => a.setupTeardown.hasSetUp).length,
            hasTearDown: analyses.filter(a => a.setupTeardown.hasTearDown).length,
            hasSetUpTestCase: analyses.filter(a => a.setupTeardown.hasSetUpTestCase).length,
            hasTearDownTestCase: analyses.filter(a => a.setupTeardown.hasTearDownTestCase).length
        };
        
        console.log(`  SetUp():          ${setupStats.hasSetUp}个文件 (${(setupStats.hasSetUp/analyses.length*100).toFixed(1)}%)`);
        console.log(`  TearDown():       ${setupStats.hasTearDown}个文件 (${(setupStats.hasTearDown/analyses.length*100).toFixed(1)}%)`);
        console.log(`  SetUpTestCase():  ${setupStats.hasSetUpTestCase}个文件 (${(setupStats.hasSetUpTestCase/analyses.length*100).toFixed(1)}%)`);
        console.log(`  TearDownTestCase(): ${setupStats.hasTearDownTestCase}个文件 (${(setupStats.hasTearDownTestCase/analyses.length*100).toFixed(1)}%)`);
        
        // 5. 高频includes
        console.log('\n【5️⃣  高频includes统计】');
        const allIncludes = {};
        analyses.forEach(a => {
            a.includes.forEach(inc => {
                allIncludes[inc] = (allIncludes[inc] || 0) + 1;
            });
        });
        
        console.log('  前20个高频includes:');
        Object.entries(allIncludes).sort((a, b) => b[1] - a[1]).slice(0, 20).forEach(([inc, count]) => {
            const ratio = (count / analyses.length * 100).toFixed(0);
            console.log(`    ✓ ${inc.padEnd(40)} - ${count}次 (${ratio}%)`);
        });
        
        // 6. BUILD.gn配置统计
        console.log('\n【6️⃣  BUILD.gn配置统计】');
        const gnAnalyses = analyses.filter(a => a.buildGn);
        
        if (gnAnalyses.length > 0) {
            const allExternalDeps = {};
            
            gnAnalyses.forEach(a => {
                a.buildGn.externalDeps.forEach(dep => {
                    allExternalDeps[dep] = (allExternalDeps[dep] || 0) + 1;
                });
            });
            
            console.log('  高频external_deps (Top 20):');
            Object.entries(allExternalDeps).sort((a, b) => b[1] - a[1]).slice(0, 20).forEach(([dep, count]) => {
                const ratio = (count / gnAnalyses.length * 100).toFixed(0);
                console.log(`    ✓ ${dep.padEnd(40)} - ${count}次 (${ratio}%)`);
            });
        }
    }

    /**
     * 保存详细分析结果
     */
    saveDetailedAnalysis(analyses) {
        const outputPath = 'core/knowledge/unittest-deep-analysis.json';
        
        // 提取核心模式
        const summary = {
            timestamp: new Date().toISOString(),
            totalFiles: analyses.length,
            
            corePatterns: {
                hwtestPatterns: this.extractHwtestPatterns(analyses),
                mockPatterns: this.extractMockPatterns(analyses),
                setupTeardownPatterns: this.extractSetupTeardownPatterns(analyses),
                buildGnPatterns: this.extractBuildGnPatterns(analyses),
                includePatterns: this.extractIncludePatterns(analyses)
            },
            
            bestExamples: this.selectBestExamples(analyses, 30)
        };
        
        fs.writeFileSync(outputPath, JSON.stringify(summary, null, 2));
        console.log(`\n✅ 详细分析已保存到: ${outputPath}`);
        console.log(`   文件大小: ${(fs.statSync(outputPath).size / 1024).toFixed(2)} KB`);
    }

    extractHwtestPatterns(analyses) {
        const levelDist = {};
        analyses.forEach(a => {
            a.hwtestCases.forEach(tc => {
                levelDist[tc.testLevel] = (levelDist[tc.testLevel] || 0) + 1;
            });
        });
        
        return {
            totalTests: analyses.reduce((sum, a) => sum + a.hwtestCases.length, 0),
            levelDistribution: Object.entries(levelDist).map(([level, count]) => ({ level, count })),
            template: 'HWTEST_F(TestClass, TestName001, TestSize.Level1)',
            examples: analyses.filter(a => a.hwtestCases.length > 0)
                .slice(0, 5)
                .map(a => ({
                    file: a.fileName,
                    cases: a.hwtestCases.slice(0, 3)
                }))
        };
    }

    extractMockPatterns(analyses) {
        const mockStats = {};
        analyses.forEach(a => {
            Object.entries(a.mockUsage).forEach(([key, value]) => {
                mockStats[key] = (mockStats[key] || 0) + value;
            });
        });
        
        return {
            frequency: mockStats,
            mostUsed: Object.entries(mockStats).sort((a, b) => b[1] - a[1]).slice(0, 10)
        };
    }

    extractSetupTeardownPatterns(analyses) {
        return {
            usageRate: {
                setUp: analyses.filter(a => a.setupTeardown.hasSetUp).length / analyses.length,
                tearDown: analyses.filter(a => a.setupTeardown.hasTearDown).length / analyses.length,
                setUpTestCase: analyses.filter(a => a.setupTeardown.hasSetUpTestCase).length / analyses.length,
                tearDownTestCase: analyses.filter(a => a.setupTeardown.hasTearDownTestCase).length / analyses.length
            }
        };
    }

    extractBuildGnPatterns(analyses) {
        const gnAnalyses = analyses.filter(a => a.buildGn);
        if (gnAnalyses.length === 0) return {};
        
        const allExternalDeps = {};
        gnAnalyses.forEach(a => {
            a.buildGn.externalDeps.forEach(dep => {
                allExternalDeps[dep] = (allExternalDeps[dep] || 0) + 1;
            });
        });
        
        return {
            highFreqExternalDeps: Object.entries(allExternalDeps)
                .sort((a, b) => b[1] - a[1])
                .slice(0, 30)
                .map(([dep, count]) => ({ dep, count, frequency: count / gnAnalyses.length }))
        };
    }

    extractIncludePatterns(analyses) {
        const allIncludes = {};
        analyses.forEach(a => {
            a.includes.forEach(inc => {
                allIncludes[inc] = (allIncludes[inc] || 0) + 1;
            });
        });
        
        return {
            highFreqIncludes: Object.entries(allIncludes)
                .sort((a, b) => b[1] - a[1])
                .slice(0, 30)
                .map(([include, count]) => ({ include, count, frequency: count / analyses.length }))
        };
    }

    selectBestExamples(analyses, count = 30) {
        // 选择最有代表性的示例
        const scored = analyses.map(a => {
            let score = 0;
            
            score += a.hwtestCases.length * 5;
            score += Object.values(a.mockUsage).reduce((sum, v) => sum + v, 0);
            if (a.setupTeardown.hasSetUp) score += 10;
            if (a.buildGn) score += 20;
            
            return { analysis: a, score };
        });
        
        return scored
            .sort((a, b) => b.score - a.score)
            .slice(0, count)
            .map(s => s.analysis);
    }

    /**
     * 主执行函数
     */
    async run() {
        console.log('🚀 开始深度学习Unittest模式...\n');
        
        const ohcodePath = 'OHCode';
        if (!fs.existsSync(ohcodePath)) {
            console.error('❌ OHCode目录不存在!');
            return;
        }
        
        // 1. 查找所有Unittest文件
        console.log('📂 正在扫描Unittest文件...');
        const testFiles = this.findAllUnittestFiles(ohcodePath);
        console.log(`✓ 找到 ${testFiles.length} 个Unittest文件\n`);
        
        // 2. 分析每个文件
        console.log('🔍 开始深度分析...');
        const analyses = [];
        let analyzed = 0;
        
        for (const file of testFiles) {
            try {
                const analysis = this.analyzeUnittestFile(file);
                analyses.push(analysis);
                analyzed++;
                
                if (analyzed % 50 === 0) {
                    console.log(`  已分析 ${analyzed}/${testFiles.length}...`);
                }
            } catch (error) {
                console.error(`  ⚠️  分析失败: ${path.basename(file)} - ${error.message}`);
            }
        }
        
        console.log(`\n✓ 完成分析 ${analyses.length} 个文件\n`);
        
        // 3. 生成统计报告
        this.generateStatistics(analyses);
        
        // 4. 保存详细分析
        this.saveDetailedAnalysis(analyses);
        
        console.log('\n' + '='.repeat(80));
        console.log('✅ 深度学习完成！');
        console.log('='.repeat(80));
    }
}

// 执行
const learner = new UnittestPatternDeepLearner();
learner.run().catch(error => {
    console.error('❌ 执行失败:', error);
});

